package com.inetools.gwetons.client.cssStyleChangerBySelector;

import java.util.logging.Level;

import com.google.gwt.core.client.JavaScriptException;
import com.google.gwt.core.client.JavaScriptObject;
import com.inetools.gwetons.client.RegExpJsni;
import com.inetools.gwetons.client.logging.JsniLogUtil;
import com.inetools.gwetons.client.logging.JsniLogUtilFactory;
import com.inetools.gwetons.client.logging.JsniLogUtilFactoryInterface;
import com.inetools.gwetons.shared.logging.LogUtil;

/**
 * DataUnitByStyleSelector class represents each element of selectorUnitArray JavaScript object
 * @author ay
 */
class DataUnitByStyleSelector {
	// For logging --------------------------------------------------------------------------------
	static String getNameForLogging() {
		return DataUnitByStyleSelector.class.getName();
	}
	
	private static JsniLogUtilFactoryInterface jsniLogUtilFactoryInterface;
		protected static JsniLogUtilFactoryInterface getJsniLogUtilFactoryInterface() {
			return jsniLogUtilFactoryInterface;
		}
		protected static void setJsniLogUtilFactoryInterface(
				JsniLogUtilFactoryInterface jsniLogUtilFactoryInterface) {
			DataUnitByStyleSelector.jsniLogUtilFactoryInterface = jsniLogUtilFactoryInterface;
			setLogUtil( null);
			setJsniLogUtil( null);
		}
	private static LogUtil logUtil;
		static LogUtil getLogUtil() {
			return DataUnitByStyleSelector.logUtil;
		}
		static void setLogUtil( LogUtil logUtil) {
			DataUnitByStyleSelector.logUtil = logUtil;
			setJsniLogUtil( null);
		}
		
	private static JsniLogUtil jsniLogUtil;
		protected static JsniLogUtil getJsniLogUtil() {
			if ( jsniLogUtil == null) {
				setJsniLogUtil( 
						JsniLogUtilFactory.getJsniLogUtil( 
								null, getLogUtil(), getNameForLogging(), getJsniLogUtilFactoryInterface())
						);
			}
			return jsniLogUtil;
		}
		protected static void setJsniLogUtil( JsniLogUtil jsniLogUtil) {
			DataUnitByStyleSelector.jsniLogUtil = jsniLogUtil;
		}
	// --------------------------------------------------------------------------------------------
		
	final JavaScriptObject dataUnitJsObj;
	
	public DataUnitByStyleSelector( JavaScriptObject dataUnitJsObj) {
		this.dataUnitJsObj = dataUnitJsObj;
	}
	
	// Utility functions -------------------------------------------------------------------------- 
	/**
	 * @param name: name of property.
	 * @return String value of property specified by name input. Or null.
	 */
	native String getStringImpl( String name) throws JavaScriptException /*-{
		// Preparations for logging ---------------------------------------------------------------
		var methodName = "getStringImpl JSNI";
		var thisJsniLogUtil 
		= @com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::getJsniLogUtil()();
		var jsniLogEntering
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getEnteringFunction()();
		var jsniLogging
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getLogFunction()();
		var jsniLogResult
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getExitingWithResultFunction()();
		// ----------------------------------------------------------------------------------------
		
		jsniLogEntering( methodName, [ name]);
		
		if ( typeof( name) != "string") {
			jsniLogging(
				@java.util.logging.Level::WARNING, 
				"Type of name input (=" + String( name) + ") is not string: "
				+ typeof( name)
				);
			jsniLogResult( methodName, null);
			return null;
		}
		var nameCopy = @com.inetools.gwetons.client.JavaScriptObjectUtil::trim(Ljava/lang/String;)( name);
			if ( nameCopy.length < 1) {
				jsniLogging(
					@java.util.logging.Level::WARNING, 
					"Value of name input is empty string. Therefore, returning null."
					);
				jsniLogResult( methodName, null);
				return null;
			}
			
		var dataUnitJsObj 
		= this.@com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::dataUnitJsObj;
			var hasSubstantialPropertyValue 
			= @com.inetools.gwetons.client.JavaScriptObjectUtil::hasSubstantialPropertyValue(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;)(
					dataUnitJsObj, nameCopy);
			if ( !hasSubstantialPropertyValue) {
				jsniLogResult( methodName, null);
				return null;
			}
			var propertyValueStr 
			= @com.inetools.gwetons.client.JavaScriptObjectUtil::trim(Ljava/lang/String;)( 
				String( dataUnitJsObj[ nameCopy]));
			
		jsniLogResult( methodName, propertyValueStr);
		return propertyValueStr;
	}-*/;
	
	native String getStringStrictImpl( JsDataPropertyIdentification propertyId) throws JavaScriptException /*-{
		// Preparations for logging ---------------------------------------------------------------
		var methodName = "getStringStrictImpl JSNI";
		var thisJsniLogUtil 
		= @com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::getJsniLogUtil()();
		var jsniLogEntering
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getEnteringFunction()();
		var jsniLogging
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getLogFunction()();
		var jsniLogResult
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getExitingWithResultFunction()();
		// ----------------------------------------------------------------------------------------
		
		jsniLogEntering( methodName, [ "propertyId(=" + String( propertyId) + ")"]);
		
		// Validations on propertyId input --------------------------------------------------------
		if ( propertyId == null) {
			jsniLogging(
				@java.util.logging.Level::SEVERE, 
				"Null is not allowed as propertyId argument value."
				);
			jsniLogResult( methodName, null);
			return null;
		}
		
		var name 
		= propertyId.@com.inetools.gwetons.client.cssStyleChangerBySelector.JsDataPropertyIdentification::getJsPropertyName()();
			if ( typeof( name) != "string") {
				jsniLogging(
					@java.util.logging.Level::SEVERE, 
					"Failed to obtain JavaScript property name out of propertyId(=" 
					+ String( propertyId) + ") argument."
					);
				jsniLogResult( methodName, null);
				return null;
			}
		
		var nameCopy = @com.inetools.gwetons.client.JavaScriptObjectUtil::trim(Ljava/lang/String;)( name);
			if ( nameCopy.length < 1) {
				jsniLogging(
					@java.util.logging.Level::WARNING, 
					"getJsPropertyName method of " + String( propertyId) 
					+ " JsDataPropertyIdentification object returned either blank or empty string."
					);
				jsniLogResult( methodName, null);
				return null;
			}
		// ----------------------------------------------------------------------------------------
			
		var dataUnitJsObj 
		= this.@com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::dataUnitJsObj;
			var hasSubstantialPropertyValue 
			= @com.inetools.gwetons.client.JavaScriptObjectUtil::hasSubstantialPropertyValue(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;)(
					dataUnitJsObj, nameCopy);
			if ( !hasSubstantialPropertyValue) {
				jsniLogResult( methodName, null);
				return null;
			}
		
		var propertyValue = dataUnitJsObj[ nameCopy];
			if ( typeof( propertyValue) != "string") {
				jsniLogging(
					@java.util.logging.Level::INFO, 
					"The type of value of " + nameCopy + " property of dataUnitJsObj JavaScript object " 
					+ "is not string: " + typeof( propertyValue)
					);
				jsniLogResult( methodName, null);
				return null;
			}
		var propertyValueStr 
		= @com.inetools.gwetons.client.JavaScriptObjectUtil::trim(Ljava/lang/String;)( propertyValue);
		if ( propertyValueStr.length < 1) {
			jsniLogging(
				@java.util.logging.Level::INFO, 
				"The value of " + nameCopy + " property of dataUnitJsObj JavaScript object " 
				+ "is either empty or blank string(s)."
				);
		}
		
		jsniLogResult( methodName, propertyValueStr);
		return propertyValueStr;
	}-*/;
	
	native void setStringImpl( String name, String value) throws JavaScriptException /*-{
		// Preparations for logging ---------------------------------------------------------------
		var methodName = "setStringImpl JSNI";
		var thisJsniLogUtil 
		= @com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::getJsniLogUtil()();
		var jsniLogEntering
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getEnteringFunction()();
		var jsniLogging
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getLogFunction()();
		var jsniLogExiting
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getExitingFunction()();
		// ----------------------------------------------------------------------------------------
		
		jsniLogEntering( methodName, "name(=" + String( name) + ")", "value(=" + String( value) + ")");
		
		if ( typeof( name) != "string") {
			jsniLogging(
				@java.util.logging.Level::WARNING, 
				"Type of name input (=" + String( name) + ") is not string: "
				+ typeof( name)
				);
			jsniLogExiting( methodName);
			return;
		}
		var nameCopy = @com.inetools.gwetons.client.JavaScriptObjectUtil::trim(Ljava/lang/String;)( name);
			if ( nameCopy.length < 1) {
				jsniLogging(
					@java.util.logging.Level::WARNING, 
					"The value of name input is either blank or empty string."
					);
				jsniLogExiting( methodName);
				return;
			}
		if ( typeof( value) == "string") {
			var valueCopy = @com.inetools.gwetons.client.JavaScriptObjectUtil::trim(Ljava/lang/String;)( 
				value);
			this[ nameCopy] = valueCopy;
			jsniLogging(
				@java.util.logging.Level::FINEST, 
				"Have set \"" + valueCopy + "\" to " + nameCopy + " property."
				);
		}
		else {
			jsniLogging(
				@java.util.logging.Level::WARNING, 
				"Type of value input (=" + String( value) + ") is not string: " + typeof( value) 
				+ ". Hence, setting null for " + nameCopy + " property instead."
				);
			this[ nameCopy] = null;
		}
		
		jsniLogExiting( methodName);
	}-*/;
	
	/**
	 * @param name: property name
	 * @return Boolean object stored in property specified by name input. Or null.
	 */
	native Boolean getBooleanImpl( JsDataPropertyIdentification propertyId) throws JavaScriptException /*-{
		// Preparations for logging ---------------------------------------------------------------
		var methodName = "getBooleanImpl JSNI";
		var thisJsniLogUtil 
		= @com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::getJsniLogUtil()();
		var jsniLogEntering
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getEnteringFunction()();
		var jsniLogging
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getLogFunction()();
		var jsniLogResult
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getExitingWithResultFunction()();
		// ----------------------------------------------------------------------------------------
		
		jsniLogEntering( methodName, [ "propertyId(=" + String( propertyId) + ")"]);
		
		var selectorStr 
		= this.@com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::getSelector()(
			);
			var selectorPropertyIdObj 
			= @com.inetools.gwetons.client.cssStyleChangerBySelector.JsDataPropertyIdentification::Selector;
			var selectorPropertyName
			= selectorPropertyIdObj.@com.inetools.gwetons.client.cssStyleChangerBySelector.JsDataPropertyIdentification::getJsPropertyName()(
				);
		
		if ( propertyId == null) {
			jsniLogging(
				@java.util.logging.Level::SEVERE, 
				"Null is not allowed as propertyId argument value. "
				+ "Happened working on data set to be set for " + String( selectorStr) 
				+ " " + String( selectorPropertyName)
				);
			jsniLogResult( methodName, null);
			return null;
		}
		
		var name 
		= propertyId.@com.inetools.gwetons.client.cssStyleChangerBySelector.JsDataPropertyIdentification::getJsPropertyName()(
			);
			if ( typeof( name) != "string") {
				jsniLogging(
					@java.util.logging.Level::SEVERE, 
					"Failed to obtain JavaScript property name out of propertyId(=" 
					+ String( propertyId) + ") argument. Happened working on data set to be set for " 
					+ String( selectorStr) + " " + String( selectorPropertyName)
					);
				jsniLogResult( methodName, null);
				return null;
			}
		
		var nameCopy = @com.inetools.gwetons.client.JavaScriptObjectUtil::trim(Ljava/lang/String;)( name);
			if ( nameCopy.length < 1) {
				jsniLogging(
					@java.util.logging.Level::WARNING, 
					"Value of jsPropertyName member field of " + String( propertyId) 
					+ " JsDataPropertyIdentification object is either blank or empty string."
					);
				jsniLogResult( methodName, null);
				return null;
			}
			
		var dataUnitJsObj 
		= this.@com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::dataUnitJsObj;
			var hasSubstantialPropertyValue 
			= @com.inetools.gwetons.client.JavaScriptObjectUtil::hasSubstantialPropertyValue(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;)(
					dataUnitJsObj, nameCopy);
			if ( !hasSubstantialPropertyValue) {
				jsniLogResult( methodName, null);
				return null;
			}
			
		if ( typeof( dataUnitJsObj[ nameCopy]) != 'boolean') {
			var selectorPropertyIdObj
			= @com.inetools.gwetons.client.cssStyleChangerBySelector.JsDataPropertyIdentification::Selector;
			var selectorPropertyName 
			= selectorPropertyIdObj.@com.inetools.gwetons.client.cssStyleChangerBySelector.JsDataPropertyIdentification::getJsPropertyName()(
				);
			jsniLogging(
				@java.util.logging.Level::WARNING, 
				"In data set to be set for " + String( selectorStr) + " " + String( selectorPropertyName)
				+ ", data value of " + nameCopy + " property is not boolean type: " 
				+ typeof( dataUnitJsObj[ nameCopy]) + ". Hence returning null instead."
				);
			jsniLogResult( methodName, null);
			return null;
		}
		
		var propertyValue = @java.lang.Boolean::valueOf(Z)( dataUnitJsObj[ nameCopy]);
			jsniLogResult( methodName, propertyValue);
		return propertyValue;
	}-*/;
	
	native void setBooleanImpl( String name, boolean value) throws JavaScriptException /*-{
		// Preparations for logging ---------------------------------------------------------------
		var methodName = "setBooleanImpl JSNI";
		var thisJsniLogUtil 
		= @com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::getJsniLogUtil()();
		var jsniLogEntering
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getEnteringFunction()();
		var jsniLogging
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getLogFunction()();
		var jsniLogExiting
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getExitingFunction()();
		// ----------------------------------------------------------------------------------------
		
		jsniLogEntering( methodName, [ "name(=" + String( name) + ")", "value(=" + String( value) + ")"]);
		
		var selectorStr 
		= this.@com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::getSelector()(
			);
			var selectorPropertyIdObj
			= @com.inetools.gwetons.client.cssStyleChangerBySelector.JsDataPropertyIdentification::Selector;
			var selectorPropertyName 
			= selectorPropertyIdObj.@com.inetools.gwetons.client.cssStyleChangerBySelector.JsDataPropertyIdentification::getJsPropertyName()(
				);

		
		if ( typeof( name) != "string") {
			jsniLogging(
				@java.util.logging.Level::WARNING, 
				"Type of name input (=" + String( name) + ") is not string: " + typeof( name) 
				+ ". Happened working on data set to be set for " 
				+ String( selectorStr) + " " + String( selectorPropertyName)
				);
			jsniLogExiting( methodName);
			return;
		}
		
		var nameCopy = @com.inetools.gwetons.client.JavaScriptObjectUtil::trim(Ljava/lang/String;)( name);
			if ( nameCopy.length < 1) {
				jsniLogging(
					@java.util.logging.Level::WARNING, 
					"The value of name input is either blank or empty string. Happened working on "
					+ "data set to be set for " + String( selectorStr) + " " + String( selectorPropertyName)
					);
				jsniLogExiting( methodName);
				return;
			}
		
		var dataUnitJsObj 
		= this.@com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::dataUnitJsObj;
			dataUnitJsObj[ nameCopy] = value;
				jsniLogging(
					@java.util.logging.Level::FINEST, 
					"In data set to be set for " + String( selectorStr) + " " 
					+ String( selectorPropertyName) + ", value of " + nameCopy 
					+ " property has been set to " + String( value) + "."
					);
					
		jsniLogExiting( methodName);
		return;
	}-*/;
	
	static JavaScriptObject hexPrefixRegExp = 
		RegExpJsni.getRegExp( "^\\s*(0\\s*x|#)\\s*[0-9a-fA-F]{1,8}\\s*$", true, false); 
		// It won't be necessary to cover 4 bytes though.
	
	/**
	 * @param hexStr: Numeric string in hex format like "0xABCDEF01"
	 * @return Rest of string part after removing "0x" prefix. i.e. "ABCDEF01". 
	 * When hexStr is not numeric string in hex format, return null.
	 */
	static String extractBesideHexPrefix( String hexStr) {
		String methodName = "extractBesideHexPrefix";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( 
				methodName, 
				new Object[]{ "hexStr(=" + ((hexStr == null) ? "null" : hexStr) + ")"}
				);
		
		// Validation on hexStr input -------------------------------------------------------------
		if ( hexStr == null) {
			logUtil.exiting( methodName, null);
			return null;
		}
		
		if ( !RegExpJsni.test( DataUnitByStyleSelector.hexPrefixRegExp, hexStr)) {
			logUtil.exiting( methodName, null);
			return null;
		}
		// ----------------------------------------------------------------------------------------
		
		String hexStrCopy = hexStr.replace( " ", "").toLowerCase();
		if ( hexStrCopy.indexOf( "x") > 0) {
			hexStrCopy = hexStrCopy.substring( hexStrCopy.indexOf( "x") + 1);
		}
		else {
			hexStrCopy = hexStrCopy.substring( hexStrCopy.indexOf( "#") + 1);
		}
		
		logUtil.exiting( methodName, hexStrCopy);
		return hexStrCopy;
	} // protected final static String removeHexPrefix( String hexStr)
	
	native Integer getIntegerImpl(String name) throws JavaScriptException /*-{
		// Preparations for logging ---------------------------------------------------------------
		var methodName = "getIntegerImpl JSNI";
		var thisJsniLogUtil 
		= @com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::getJsniLogUtil()();
		var jsniLogEntering
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getEnteringFunction()();
		var jsniLogging
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getLogFunction()();
		var jsniLogResult
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getExitingWithResultFunction()();
		// ----------------------------------------------------------------------------------------
		
		jsniLogEntering( methodName, [ "name(=" + String( name) + ")"]);
			
		var selectorStr 
		= this.@com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::getSelector()(
			);
			var selectorPropertyIdObj
			= @com.inetools.gwetons.client.cssStyleChangerBySelector.JsDataPropertyIdentification::Selector;
			var selectorPropertyName 
			= selectorPropertyIdObj.@com.inetools.gwetons.client.cssStyleChangerBySelector.JsDataPropertyIdentification::getJsPropertyName()(
				);
		
		if ( typeof( name) != "string") {
			jsniLogging(
				@java.util.logging.Level::WARNING, 
				"Type of name input (=" + String( name) + ") is not string: " + typeof( name) + ". "
				+ "Happened working on data set to be set for " 
				+ String( selectorStr) + " " + String( selectorPropertyName)
				);
			jsniLogResult( methodName, null);
			return null;
		}
		
		var nameCopy = @com.inetools.gwetons.client.JavaScriptObjectUtil::trim(Ljava/lang/String;)( name);
			if ( nameCopy.length < 1) {
				jsniLogging(
					@java.util.logging.Level::WARNING, 
					"The value of name input is either blank or empty string. "
					+ "Happened working on data set to be set for " 
					+ String( selectorStr) + " " + String( selectorPropertyName)
					);
				jsniLogResult( methodName, null);
				return null;
			}
			
		var dataUnitJsObj 
		= this.@com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::dataUnitJsObj;
		if ( typeof( dataUnitJsObj[ nameCopy]) != 'number') {
			jsniLogging(
				@java.util.logging.Level::WARNING, 
				"In data set to be set for " + String( selectorStr) + " " 
				+ String( selectorPropertyName) + ", value of " + nameCopy 
				+ " property is not number type: " + typeof( dataUnitJsObj[ nameCopy]) 
				+ ". Hence returning null instead."
				);
			jsniLogResult( methodName, null);
			return null;
		}
		
		var intValue = parseInt( dataUnitJsObj[ nameCopy]);
		if ( isNaN( intValue)) {
			jsniLogging(
				@java.util.logging.Level::WARNING, 
				"In data set to be set for " + String( selectorStr) + " " 
				+ String( selectorPropertyName) + ", failed to parse the value(=" 
				+ String( dataUnitJsObj[ nameCopy]) + ") of " + nameCopy 
				+ " property as integer value. Hence returning null instead."
				);
			jsniLogResult( methodName, null);
			return null;
		}
		
		jsniLogResult( methodName, intValue);
		return @java.lang.Integer::valueOf(I)( intValue);
	}-*/;
	
	native void setIntegerImpl( String name, int value) throws JavaScriptException /*-{
		// Just logging preparation ---------------------------------------------------------------
		var methodName = "setIntegerImpl JSNI";
		var thisJsniLogUtil 
		= @com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::getJsniLogUtil()();
		var jsniLogEntering
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getEnteringFunction()();
		var jsniLogging
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getLogFunction()();
		var jsniLogExiting
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getExitingFunction()();
		// ----------------------------------------------------------------------------------------
		
		jsniLogEntering( methodName, [ "name(=" + String( name) + ")", "value(=" + String( value) + ")"]);
		
		var selectorStr 
		= this.@com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::getSelector()(
			);
			var selectorPropertyIdObj 
			= @com.inetools.gwetons.client.cssStyleChangerBySelector.JsDataPropertyIdentification::Selector;
			var selectorPropertyName
			= selectorPropertyIdObj.@com.inetools.gwetons.client.cssStyleChangerBySelector.JsDataPropertyIdentification::getJsPropertyName()(
				);
		
		if ( typeof( name) != "string") {
			jsniLogging(
				@java.util.logging.Level::SEVERE, 
				"Type of name input (=" + String( name) + ") is not string: "
				+ typeof( name) + ". Happened working on data set to be set for " 
				+ String( selectorStr) + " " + String( selectorPropertyName)
				);
			jsniLogExiting( methodName);
			return;
		}
		
		var nameCopy = @com.inetools.gwetons.client.JavaScriptObjectUtil::trim(Ljava/lang/String;)( name);
			if ( nameCopy.length < 1) {
				jsniLogging(
					@java.util.logging.Level::SEVERE, 
					"The value of name input is either blank or empty string. "
					+ "Happened working on data set to be set for " 
					+ String( selectorStr) + " " + String( selectorPropertyName)
					);
				jsniLogExiting( methodName);
				return;
			}
			
		var dataUnitJsObj 
		= this.@com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::dataUnitJsObj;
		if ( typeof( dataUnitJsObj[ nameCopy]) != 'number') {
			jsniLogging(
				@java.util.logging.Level::INFO,
				"In data set to be set for " + String( selectorStr) + " " 
				+ String( selectorPropertyName) + ", pre-set value of " + nameCopy 
				+ " property is not number type: " + typeof( dataUnitJsObj[ nameCopy]) + "."
				);
		}
		
		dataUnitJsObj[ nameCopy] = value;
		
		jsniLogging(
			@java.util.logging.Level::FINER,
			"In data set to be set for " + String( selectorStr) + " " + String( selectorPropertyName) 
			+ ", have set " + String( value) + " to " + String( nameCopy) + " property."
			);
		jsniLogExiting( methodName);
		return;
	}-*/;
	
	/**
	 * To get value of either initValue or endValue javascript property 
	 */
	String getValueStr( JsDataPropertyIdentification jsDataPropertyIdentification) {
		if ( jsDataPropertyIdentification == null) {
			throw new IllegalArgumentException( "null value for propertyNames argument is not allowed.");
		}

		String methodName = "getValueStr";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, new Object[]{ jsDataPropertyIdentification});
		
		boolean isStringType = false;
		boolean isIntegerType = false;
			for( Class<?> typeObj : jsDataPropertyIdentification.getTypes()) {
				if ( typeObj.equals( String.class)) {
					isStringType = true;
				}
				if ( typeObj.equals( Integer.class)) {
					isIntegerType = true;
				}
			} // for
			if ( !isStringType) {
				throw new IllegalArgumentException( 
						jsDataPropertyIdentification.toString() + " is not appropriate as input. " 
						+ "Only property what can have string type value is allowed as input." 
						);
			}
		
		String valuePropertyNameStr = jsDataPropertyIdentification.getJsPropertyName();
		
		String valueStr = getStringImpl( valuePropertyNameStr);
			if ( valueStr != null) {
				valueStr = valueStr.trim();
				setStringImpl( valuePropertyNameStr, valueStr);
				
				if ( isIntegerType) {
					try {
						String substantialHexStr 
						= DataUnitByStyleSelector.extractBesideHexPrefix( valueStr);
						Integer integerValue = null;
							if ( substantialHexStr != null) { // valueStr is in hex format
								integerValue = Integer.parseInt( substantialHexStr, 16);
							}
							else {
								integerValue = Integer.parseInt( valueStr.replace( " ", ""));
							}
						setIntegerImpl( valuePropertyNameStr, integerValue.intValue());
						valueStr = integerValue.toString();
					}
					catch( Exception exception) { // Do nothing
					}
				}
			}
		
		logUtil.exiting( methodName, valueStr);
		return valueStr;
	} // protected final String getValueStr( JsDataPropertyIdentification jsDataPropertyIdentification)
	
	static String getRGBColorHexStr( int color) {
		String methodName = "getRGBColorHexStr";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, new Object[]{ color});
		
		String colorStr = Integer.toHexString( color);
		if ( colorStr.length() > 6) {
			colorStr = colorStr.substring( 0, 6);
		}
		else {
			String complementDigitStr = "0";
			if ( color < 0) complementDigitStr = "F";
			while( colorStr.length() < 6) {
				colorStr = complementDigitStr + colorStr;
			} // while
		}
		
		logUtil.exiting( methodName, colorStr);
		return colorStr;
	} // protected String getRGBColorHexStr( int color)
	
	static int[] getRGBColorElements( int color) {
		String methodName = "getRGBColorElements";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, new Object[]{ color});
		
		String colorStr = getRGBColorHexStr( color);
		
		int blue = Integer.parseInt( colorStr.substring( colorStr.length() - 2), 16);
		int green = Integer.parseInt( colorStr.substring( colorStr.length() - 4, colorStr.length() - 2), 16);
		int red = Integer.parseInt( colorStr.substring( colorStr.length() - 6, colorStr.length() - 4), 16);
		
		int[] rgbArray = new int[]{ red, green, blue};
		
		logUtil.exiting( methodName, rgbArray);
		return rgbArray;
	} // protected int[] getRGBColorElements( int color)
	
	static String get2ByteHexStringValue( int colorComponent) {
		String methodName = "get2ByteHexStringValue";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, new Object[]{ colorComponent});
		
		String colorStr = Integer.toHexString( colorComponent);
			while( colorStr.length() < 2) {
				colorStr = "0" + colorStr;
			} // while
			
			colorStr = colorStr.substring( colorStr.length() - 2);
		
		logUtil.exiting( methodName, colorStr);
		return colorStr;
	}
	
	/**
	 * Change css style rule which already exists in supported-media-type style sheets. 
	 * If it does not exist, then the css style rule will be added to all supported-media-type style sheets.
	 * If supported-media-type style sheets does not exist, then a create style sheet and 
	 * add the css style rule to it. 
	 * Note: Decided to add style to all supported-media-type style sheets, since it will be hard to 
	 * distinguish style sheets which is root and supported media type. 
	 * @param styleSelector
	 */
	static native boolean addCssRuleToStylesheet( String styleSelector, String styleStr, String valueStr) 
	throws JavaScriptException /*-{
		// For logging ----------------------------------------------------------------------------
		var methodName = "addCssRuleToStylesheet JSNI";
		var thisJsniLogUtil 
		= @com.inetools.gwetons.client.cssStyleChangerBySelector.DataUnitByStyleSelector::getJsniLogUtil()();
		var jsniLogEntering
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getEnteringFunction()();
		var jsniLogging
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getLogFunction()();
		var jsniLogResult
		= thisJsniLogUtil.@com.inetools.gwetons.client.logging.JsniLogUtil::getExitingWithResultFunction()();
		// ----------------------------------------------------------------------------------------
		
		jsniLogEntering( 
			methodName, 
			[ "styleSelector(=" + String( styleSelector) + ")", 
				"styleStr(=" + String( styleStr) + ")", 
				"valueStr(=" + String( valueStr) + ")"
			]);

		// Validity check on inputs ---------------------------------------------------------------
		if ( typeof( styleSelector) != "string") {
			jsniLogging(
				@java.util.logging.Level::WARNING, 
				"Type of styleSelector input is not string: " + typeof( styleSelector)
				);
			jsniLogResult( methodName, false);
			return false;
		}
		// Trim styleSelectorStr
		var styleSelectorCopy = styleSelector.replace( new RegExp( "^\\s*"), "");
		styleSelectorCopy = styleSelectorStr.replace( new RegExp( "\\s*$"), "");
			if ( styleSelectorCopy.length < 1) {
				jsniLogging(
					@java.util.logging.Level::WARNING, 
					"empty string or just blank strings is not allowed as styleSelector input value."
					);
				jsniLogResult( methodName, false);
				return false;
			}

		if ( typeof( styleStr) != "string") {
			jsniLogging(
				@java.util.logging.Level::WARNING, 
				"Type of styleStr input is not string: " + typeof( styleStr)
				);
			jsniLogResult( methodName, false);
			return false;
		}
		var styleStrCopy = styleStr.replace( " ", "");
			if ( styleStrCopy.length < 1) {
				jsniLogging(
					@java.util.logging.Level::WARNING, 
					"empty string or just blank strings is not allowed as styleStr input value."
					);
				jsniLogResult( methodName, false);
				return false;
			}
		
		if ( typeof( valueStr) != "string") {
			jsniLogging(
				@java.util.logging.Level::WARNING, 
				"Type of valueStr input is not string: " + typeof( styleStr)
				);
			jsniLogResult( methodName, false);
			return false;
		}
		// ----------------------------------------------------------------------------------------
		
		// Sanity check on $doc.styleSheets -------------------------------------------------------
		var sanityCheckStyleSheetsObjResult 
		= @com.inetools.gwetons.client.cssStyleChangerBySelector.CssStyleChangerBySelector::sanityCheckStyleSheetsObj()(
			);
		if ( !sanityCheckStyleSheetsObjResult) {
			jsniLogResult( methodName, false);
			return false;
		}
		// ----------------------------------------------------------------------------------------

		// Store indexes of style sheets (which have been loaded from same domain)
		var styleSheetsIndexArray = new Array();
		
		// Store css style rule object of which selector value is identified by styleSelector
		var cssRuleObjArray = new Array();

		// Check whether styleSelectorCopy style selector exists in any style sheet ---------------
		for( var styleSheetPropertyIndex in $doc.styleSheets) {
			if ( isNaN( styleSheetPropertyIndex)) continue;
			
			var mediaTypeCheckResult 
			= @com.inetools.gwetons.client.cssStyleChangerBySelector.CssStyleChangerBySelector::isStyleSheetMediaTypeSupported(I)(
				styleSheetPropertyIndex);
			if ( !mediaTypeCheckResult) continue; // for
			
			styleSheetsIndexArray.push( styleSheetPropertyIndex);
			
			var styleSheetElement = $doc.styleSheets[ styleSheetPropertyIndex];
			var styleSheetPointerStr
			= @com.inetools.gwetons.client.cssStyleChangerBySelector.CssStyleChangerBySelector::getStyleSheetPointer(I)( 
				styleSheetPropertyIndex);
			try {
				if ( styleSheetElement.rules) { // for IE: this needs to come ahead since IE also has different cssRules 
					for( var cssRuleIndex in styleSheetElement.rules) {
						if ( isNaN( cssRuleIndex)) continue;
						
						var cssRuleObj = styleSheetElement.rules[ cssRuleIndex];
						if ( typeof( cssRuleObj.selectorText) == "string") {
							if ( cssRuleObj.selectorText.toUpperCase() == styleSelectorStrCopy.toUpperCase()) {
							// IE capitalizes the selectorText portion
								cssRuleObj.style[ styleStr] = valueStr;
								cssRuleObjArray.push( cssRuleObj);
									jsniLogging(
										@java.util.logging.Level::FINEST, 
										"Successfully set \"" + String( valueStr) + "\" to " 
										+ String( styleStr) + " style property of rules[" 
										+ String( cssRuleIndex) + "] of " + styleSheetPointerStr 
										+ " style sheet." 
										);
								continue;
							}
						}
					} // for
				}
				else if ( styleSheetElement.cssRules) { // Standard browser
					for( var cssRuleIndex in styleSheetElement.cssRules) {
						if ( isNaN( cssRuleIndex)) continue;
						
						var cssRuleObj = styleSheetElement.cssRules[ cssRuleIndex];
						if ( typeof( cssRuleObj.selectorText) == "string") {
							if ( cssRuleObj.selectorText.toUpperCase() == styleSelectorStrCopy.toUpperCase()) {
							// IE capitalizes the selectorText portion
								cssRuleObj.style[ styleStr] = valueStr;
								cssRuleObjArray.push( cssRuleObj);
									jsniLogging(
										@java.util.logging.Level::FINEST, 
										"Successfully set \"" + String( valueStr) + "\" to " 
										+ String( styleStr) + " style property of cssRules[" 
										+ String(cssRuleIndex) + "] of " + styleSheetPointerStr 
										+ " style sheet." 
										);
								continue;
							}
						}
					} // for
				}
			}
			catch( exception) { 
			// Catch access deinded error by accessing stylesheet loaded from other domain
				var errorMessage 
				= "Skipped processing the stylesheet " + styleSheetPointerStr 
				+ " due to this error: " + String( exception); 
				jsniLogging(
					@java.util.logging.Level::INFO, 
					errorMessage);
				continue; // for
			}
		} // for
		// ----------------------------------------------------------------------------------------

		// CSS style rule of which selector is identified by styleSelector string has already existed
		if ( cssRuleObjArray.length > 0) {
			jsniLogResult( methodName, true);
			return true;
		}

		// Add a style sheet ----------------------------------------------------------------------
		if ( styleSheetsIndexArray.length < 1) {
			jsniLogging(
				@java.util.logging.Level::INFO, 
				"Going to create a style sheet since no style sheet was found."
				);
				
			var headElement; 
				var headElementsCollection = $doc.getElementsByTagName( "head");
	 			if ( headElementsCollection.length < 1) { // Could be not HTML
	 				var htmlElementsCollection = $doc.getElementsByTagName( "html");
	 				if ( htmlElementsCollection.length < 1) { // It's not HTML
						jsniLogging(
							@java.util.logging.Level::SEVERE, 
							"Could not find html DOM element.");
						jsniLogResult( methodName, false);
	 					return false; 
	 				}
	 				
	 				// Add head element
	 				headElement = document.createElement( "head");
	 				htmlElementsCollection.appendChild( headElement);
	 			}
	 			else {
					headElement = headElementsCollection[ 0];
	 			}
 			
			var styleElement = document.createElement( "style");
			styleElement.setAttribute( "type", "text/css");
			headElement.appendChild( styleElement);
		
			styleSheetsIndexArray.push( $doc.styleSheets.length);
		}
		// ----------------------------------------------------------------------------------------

		// Add css style rule to all supported-media-type style sheets ----------------------------
		var styleChangeDone = false;
		for( var index in styleSheetsIndexArray) {
			if ( isNaN( index)) continue; // for
			
			var styleSheet = $doc.styleSheets[ styleSheetsIndexArray[ index]];
			if ( typeof( styleSheet) == "undefined") {
				jsniLogging(
					@java.util.logging.Level::WARNING,	
					"Unexpected inconsistent state: styleSheetsIndexArray[" + String( index) + "] holds "
					+ "index value (=" + String(styleSheetsIndexArray[ index]) + ") what should point "
					+ "one of existing style sheets but it does not."
					);
				continue; // for
			}
			var styleSheetPointerStr
			= @com.inetools.gwetons.client.cssStyleChangerBySelector.CssStyleChangerBySelector::getStyleSheetPointer(I)( 
				styleSheetsIndexArray[ index]);
			if ( typeof( styleSheet.addRule) == "function") { // IE
				styleSheet.addRule( styleSelector, styleStr + ":" + valueStr);
				styleChangeDone = true;
					jsniLogging(
						@java.util.logging.Level::FINEST,	
						"Successfully added \"" + String( valueStr) + "\" for " + String( styleStr) 
						+ " style for " + String( styleSelector) + " selector in " + styleSheetPointerStr 
						+ " style sheet"
						);
			}
			else if ( typeof( styleSheet.insertRule) == "function") { // Standard browser
				styleSheet.insertRule( 
					styleSelector + " {" + styleStr + ":" + valueStr + "}" , 
					styleSheet.cssRules.length
					);
				styleChangeDone = true;
					jsniLogging(
						@java.util.logging.Level::FINEST,	
						"Successfully added \"" + String( valueStr) + "\" for " + String( styleStr) 
						+ " style for " + String( styleSelector) + " selector in " + styleSheetPointerStr 
						+ " style sheet"
						);
			}
		} // for
		// ----------------------------------------------------------------------------------------

		jsniLogResult( methodName, styleChangeDone);
		return styleChangeDone;
	}-*/; // protected final native void addCssRuleToStylesheet( String styleSelector, String styleStr, String valueStr)

	// --------------------------------------------------------------------------------------------
	
	/**
	 * @return String representing value of selector JavaScript property of 
	 * selectorUnitArray JavaScript object. 
	 * When it's null, return empty string instead.
	 */
	public String getSelector() {
		String methodName = "getSelector";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, null);
		
		String selector = getStringStrictImpl( JsDataPropertyIdentification.Selector);
			if ( selector == null) {
				selector = "";
				logUtil.log( 
						Level.SEVERE, 
						"Value of " + JsDataPropertyIdentification.Selector.getJsPropertyName() 
						+ " JavaScript property in the data set is null. Returning empty string instead."
						);
			}
			else if ( "".equals( selector)) {
				logUtil.log( 
						Level.SEVERE, 
						"Value of " + JsDataPropertyIdentification.Selector.getJsPropertyName() 
						+ " JavaScript property in the data set is empty or blank string(s)."
						);
			}
		
		logUtil.exiting( methodName, selector);
		return selector;
	}		
	/**
	 * @return String representing value of style JavaScript property of 
	 * selectorUnitArray JavaScript object. 
	 * When it's null, return empty string instead.
	 */
	public String getStyle() {
		String methodName = "getStyle";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, null);
		
		String style = getStringStrictImpl( JsDataPropertyIdentification.Style);
			if ( style == null) {
				style = "";
				logUtil.log( 
						Level.SEVERE, 
						"In data set to be set for " + getSelector() + " " 
						+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", "
						+ "data value of " + JsDataPropertyIdentification.Style.getJsPropertyName() 
						+ " property is null. Returning empty string instead."
						);
			}
			else if ( "".equals( style)) {
				logUtil.log( 
						Level.SEVERE, 
						"In data set to be set for " + getSelector() + " " 
						+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", "
						+ "data value of " + JsDataPropertyIdentification.Style.getJsPropertyName() 
						+ " property is empty or blank string(s)."
						);
			}
		
		logUtil.exiting( methodName, style);
		return style;
	}
	
	/**
	 * @return boolean value of isNumericColor JavaScript property. 
	 * false when value of either initValue property or endValue property is not numeric.  
	 */
	public boolean isNumericColor() {
		String methodName = "isStyleForColor";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, null);
		
		Boolean booleanObj = null;
			try {
				booleanObj = getBooleanImpl( JsDataPropertyIdentification.IsNumericColor);
			}
			catch( Throwable throwable) { // Do nothing
				logUtil.log( 
						Level.SEVERE, 
						"In data set to be set for " + getSelector() + " " 
						+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", "
						+ "data value of " + JsDataPropertyIdentification.IsNumericColor.getJsPropertyName() 
						+ " JavaScript property is not boolean type.", 
						throwable);
			}
		if ( !Boolean.TRUE.equals( booleanObj)) {
			logUtil.exiting( methodName, false);
			return false;
		}
		
		if ( !isInitValueNumeric()) {
			logUtil.log( 
					Level.WARNING, 
					"In data set to be set for " + getSelector() + " " 
					+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", though " 
					+ JsDataPropertyIdentification.IsNumericColor.getJsPropertyName() + " property value " 
					+ "is true, " + JsDataPropertyIdentification.InitValue.getJsPropertyName() 
					+ " property holds non-numeric value."
					);
			logUtil.exiting( methodName, false);
			return false;
		}
		
		if ( !isEndValueNumeric()) {
			logUtil.log( 
					Level.WARNING, 
					"In data set to be set for " + getSelector() + " " 
					+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", though " 
					+ JsDataPropertyIdentification.IsNumericColor.getJsPropertyName() + " property value " 
					+ "is true, " + JsDataPropertyIdentification.EndValue.getJsPropertyName() 
					+ " property holds non-numeric value."
					);
			logUtil.exiting( methodName, false);
			return false;
		}
		
		logUtil.exiting( methodName, true);
		return true;
	}
	
	// About initValue ------------------------------------------------------------------------
	String initValueStr = null;	
	Integer initValueObj = null;
		boolean isInitValueLoaded = false;
			boolean isInitValueLoaded() {
				return isInitValueLoaded;
			}
			void setInitValueLoaded( boolean isInitValueLoaded) {
				this.isInitValueLoaded = isInitValueLoaded;
			}
		boolean isInitValueNumeric = false;
			void setInitValueNumeric( boolean isInitValueNumeric) {
				this.isInitValueNumeric = isInitValueNumeric;
			}

	/**
	 * When initValue javascript property is numeric string in hex format, then initValue javascript 
	 * property will be set to decimal representation of that hex value.
	 * When value of initValue JavaScript property is null, then style is untouched until when value of 
	 * endValue property will be set.
	 * When value of initValue JavaScript property is empty string, then style will be cleared. 
	 * Set value to numericInitValueOn javascript property based on whether 
	 * value of initValue javascript property is string representation of integer.
	 * @return string value read from initValue javascript property or empty string.
	 */
	public String getInitValueStr() {
		String methodName = "getInitValueStr";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, null);
		
		if ( isInitValueLoaded()) {
			logUtil.exiting( methodName, initValueStr);
			return initValueStr; 
		}
		
		initValueStr = getValueStr( JsDataPropertyIdentification.InitValue);
			if ( initValueStr == null) {
				logUtil.log( 
						Level.INFO, 
						"In data set to be set for " + getSelector() + " " 
						+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", "
						+ "data value of " + JsDataPropertyIdentification.InitValue.getJsPropertyName() 
						+ " property is null."
						);
			}
			else if ( "".equals( initValueStr)) {
				logUtil.log( 
						Level.INFO, 
						"In data set to be set for " + getSelector() + " " 
						+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", "
						+ "data value of " + JsDataPropertyIdentification.InitValue.getJsPropertyName() 
						+ " property is empty string."
						);
			}
			else {
				try {
					initValueObj = Integer.valueOf( initValueStr);
					setInitValueNumeric( true);
				}
				catch( Throwable throwable) {
					logUtil.log( 
							Level.FINEST, 
							"In data set to be set for " + getSelector() + " " 
							+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", "
							+ "data value of " + JsDataPropertyIdentification.InitValue.toString() 
							+ " property is not numeric."
							);
				}
			}
			
		setInitValueLoaded( true);
		
		logUtil.exiting( methodName, initValueStr);
		return initValueStr;
	} // public final String getInitValueStr()
	
	public boolean isInitValueNumeric() {
		String methodName = "isNumericInitValueOn";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, null);
		
		if ( isInitValueLoaded()) {
			logUtil.exiting( methodName, isInitValueNumeric);
			return isInitValueNumeric; 
		}
		
		getInitValueStr();
		
		logUtil.exiting( methodName, isInitValueNumeric);
		return isInitValueNumeric; 
	} // public final Boolean isNumericInitValueOn()
	
	/**
	 * @return Integer object representing value of intValue JavaScript property. 
	 * Null when value of intValue JavaScript property cannot be represented by Integer type.
	 */
	public Integer getInitValue() {
		String methodName = "getInitValue";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, null);
		
		if ( isInitValueLoaded()) {
			logUtil.exiting( methodName, initValueObj);
			return initValueObj; 
		}
		
		getInitValueStr();
		
		logUtil.exiting( methodName, initValueObj);
		return initValueObj; 
	} // public final Integer getInitValue()
	// ----------------------------------------------------------------------------------------
	
	// About endValue -------------------------------------------------------------------------
//TODO Need to consider the case that endValue javascript property is overridden between event processing
	String endValueStr = null;
	Integer endValueObj = null;
		boolean isEndValueLoaded = false;
			boolean isEndValueLoaded() {
				return isEndValueLoaded;
			}
			void setEndValueLoaded( boolean isEndValueLoaded) {
				this.isEndValueLoaded = isEndValueLoaded;
			}
		boolean isEndValueNumeric = false;
			void setEndValueNumeric( boolean isEndValueNumeric) {
				this.isEndValueNumeric = isEndValueNumeric;
			}

	/**
	 * When endValue javascript property is numeric string in hex format, then endValue javascript 
	 * property will be set to decimal representation of that hex value.
	 * When value of endValue JavaScript property is null, then style will be left with value of 
	 * initValue property that has been set before.
	 * When value of endValue JavaScript property is empty string, then style will be cleared. 
	 * Set value to numericEndValueOn javascript property based on whether 
	 * value of endValue javascript property is string representation of integer.
	 * @return string value (including empty string or null) read from endValue javascript property.
	 */
	public String getEndValueStr() {
		String methodName = "getEndValueStr";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering(  methodName, null);
		
		if ( isEndValueLoaded()) {
			logUtil.exiting( methodName, endValueStr);
			return endValueStr;
		}
		
		endValueStr = getValueStr( JsDataPropertyIdentification.EndValue);
			if ( endValueStr == null) {
				logUtil.log( 
						Level.INFO, 
						"In data set to be set for " + getSelector() + " " 
						+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", "
						+ "data value of raw " + JsDataPropertyIdentification.EndValue.getJsPropertyName() 
						+ " property is null."
						);
			}
			else if ( "".equals( endValueStr)) {
				logUtil.log( 
						Level.INFO, 
						"In data set to be set for " + getSelector() + " " 
						+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", "
						+ " data value of raw " + JsDataPropertyIdentification.EndValue.getJsPropertyName() 
						+ " property is empty string."
						);
			}
			else {
				try {
					endValueObj = Integer.valueOf( endValueStr);
					setEndValueNumeric( true);
				}
				catch( Throwable throwable) {
					logUtil.log( 
							Level.FINEST, 
							"In data set to be set for " + getSelector() + " " 
							+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", "
							+ " data value of " + JsDataPropertyIdentification.EndValue.getJsPropertyName() 
							+ " property is not numeric."
							);
				}
			}
		
		setEndValueLoaded( true);
		
		logUtil.exiting( methodName, endValueStr);
		return endValueStr;
	} // public final String getEndValueStr()
	
	public Boolean isEndValueNumeric() {
		String methodName = "isEndValueNumeric";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, null);
		
		if ( isEndValueLoaded()) {
			logUtil.exiting( methodName, isEndValueNumeric);
			return isEndValueNumeric;
		}
		
		getEndValueStr();
		
		logUtil.exiting( methodName, isEndValueNumeric);
		return isEndValueNumeric;
	}
	/**
	 * @return Integer object representing value of endValue JavaScript property. 
	 * Null when value of endValue JavaScript property cannot be represented by Integer type.
	 */
	public Integer getEndValue() {
		String methodName = "getEndValue";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, null);
		
		if ( isEndValueLoaded()) {
			logUtil.exiting( methodName, endValueObj);
			return endValueObj; 
		}
		
		getEndValueStr();
		
		logUtil.exiting( methodName, endValueObj);
		return endValueObj;
	} // public final Integer getEndValue()
	// ----------------------------------------------------------------------------------------
	
	/**
	 * @return String representing value of valueUnit JavaScript property of 
	 * selectorUnitArray JavaScript object. 
	 * When it's null, return empty string instead.
	 */
	public final String getValueUnit() {
		String methodName = "getValueUnit";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, null);
		
		String valueUnitStr = getStringStrictImpl( JsDataPropertyIdentification.ValueUnit);
			if ( valueUnitStr == null) {
				valueUnitStr = "";
			}
			
		logUtil.exiting( methodName, "\"" + valueUnitStr + "\"");
		return valueUnitStr;
	}
	/**
	 * @return String representing value of valuePrefix JavaScript property of 
	 * selectorUnitArray JavaScript object. 
	 * When it's null, return empty string instead.
	 */
	public final String getValuePrefix() {
		String methodName = "getValuePrefix";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, null);
		
		String valuePrefixStr 
		= getStringStrictImpl( JsDataPropertyIdentification.ValuePrefix);
			if ( valuePrefixStr == null) {
				valuePrefixStr = "";
			}
		
		logUtil.exiting( methodName, "\"" + valuePrefixStr + "\"");
		return valuePrefixStr;
	}
	/**
	 * @return String representing value of valueSuffix JavaScript property of 
	 * selectorUnitArray JavaScript object. 
	 * When it's null, return empty string instead.  
	 */
	public final String getValueSuffix() {
		String methodName = "getValueSuffix";
		LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
		
		logUtil.entering( methodName, null);
		
		String valueSuffixStr 
		= getStringStrictImpl( JsDataPropertyIdentification.ValueSuffix);
			if ( valueSuffixStr == null) {
				valueSuffixStr = "";
			}
		
		logUtil.exiting( methodName, "\"" + valueSuffixStr + "\"");
		return valueSuffixStr;
	}
	
	// About period -------------------------------------------------------------------------------
	Integer preiodObj = null;
		public Integer getPeriod() {
			String methodName = "getPeriod";
			LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
			
			logUtil.entering( methodName, null);
			
			if ( preiodObj != null) {
				logUtil.exiting( methodName, preiodObj);
				return preiodObj;
			}
			
			preiodObj = getIntegerImpl( JsDataPropertyIdentification.Period.getJsPropertyName());
			if ( preiodObj == null) {
				preiodObj = new Integer( CssStyleChangerBySelector.getMinimumPeriod());
			}
			else {
				if ( preiodObj.intValue() < CssStyleChangerBySelector.getMinimumPeriod()) {
					logUtil.log( 
							Level.INFO, 
							"In data set to be set for " + getSelector() + " " 
							+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", "
							+ "set value of " + JsDataPropertyIdentification.Period.getJsPropertyName()  
							+ " property to minimum period (=" + CssStyleChangerBySelector.getMinimumPeriod() 
							+ ") since " + preiodObj.toString() + " is smaller than minimum period."
							);
					preiodObj = new Integer( CssStyleChangerBySelector.getMinimumPeriod());
				}
				logUtil.exiting( methodName, preiodObj);
				return preiodObj;
			}
			
			logUtil.exiting( methodName, preiodObj);
			return preiodObj;
		}
	// --------------------------------------------------------------------------------------------	
	
	// About interval -----------------------------------------------------------------------------
	Integer intervalObj = null;
		public Integer getInterval() {
			String methodName = "getInterval";
			LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
			
			logUtil.entering( methodName, null);
			
			if ( intervalObj != null) {
				logUtil.exiting( methodName, intervalObj);
				return intervalObj;
			}
			
			intervalObj = getIntegerImpl( JsDataPropertyIdentification.Interval.getJsPropertyName());
				if ( intervalObj == null) {
					intervalObj = new Integer( CssStyleChangerBySelector.getMinimumInterval());
				}
				else {
					if ( intervalObj.intValue() < CssStyleChangerBySelector.getMinimumInterval()) {
						logUtil.log( 
								Level.INFO, 
								"In data set to be set for " + getSelector() + " " 
								+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", "
								+ "set value of " + JsDataPropertyIdentification.Interval.getJsPropertyName() 
								+ " property to minimum interval (=" 
								+ CssStyleChangerBySelector.getMinimumInterval() + ") " 
								+ "since " + intervalObj.toString() + " is smaller than minimum interval."
								);
						intervalObj = new Integer( CssStyleChangerBySelector.getMinimumInterval());
					}
					logUtil.exiting( methodName, intervalObj);
					return intervalObj;
				}
	
			logUtil.exiting( methodName, intervalObj);
			return intervalObj;
		}
	// --------------------------------------------------------------------------------------------

	// About reversible ---------------------------------------------------------------------------
	Boolean reversibleObj = null;
		public Boolean getReversible() {
			String methodName = "getReversible";
			LogUtil logUtil = DataUnitByStyleSelector.getJsniLogUtil().getLogUtil(); 
			
			logUtil.entering( methodName, null);
			
			if ( reversibleObj != null) {
				logUtil.exiting( methodName, reversibleObj);
				return reversibleObj;
			}
			
			reversibleObj = getBooleanImpl( JsDataPropertyIdentification.Reversible);
				if ( reversibleObj == null) {
					reversibleObj = new Boolean( false);
					logUtil.log( 
							Level.INFO, 
							"In data set to be set for " + getSelector() + " " 
							+ JsDataPropertyIdentification.Selector.getJsPropertyName() + ", "
							+ "set value of " + JsDataPropertyIdentification.Reversible.getJsPropertyName() 
							+ " property to false because of failure in reading it."
							);
				}
			
			logUtil.exiting( methodName, reversibleObj);
			return reversibleObj;
		}
	
	boolean inReverse = false;
		public boolean isInReverse() {
			return inReverse;
		}
		void setInReverse( boolean inReverse) {
			this.inReverse = inReverse;
		}
	
	// --------------------------------------------------------------------------------------------
	
	String styleValueStr;	// will be initialized by StyleChangerTimerEventManager.prepDataUnitByStyleSelectorObjs method
		public String getStyleValueStr() {
			return styleValueStr;
		}
		void setStyleValueStr(String styleValueStr) {
			this.styleValueStr = styleValueStr;
		}

	StyleChangerState styleChangerState = new StyleChangerState();
}
